﻿//CandleSeries.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Algo.Candles
{
	using System;
	using System.Linq;

	using Ecng.Common;
	using Ecng.Configuration;
	using Ecng.Serialization;

	using StockSharp.BusinessEntities;

	/// <summary>
	/// Серия свечек.
	/// </summary>
	public class CandleSeries : Disposable, IPersistable
	{
		/// <summary>
		/// Создать <see cref="CandleSeries"/>.
		/// </summary>
		public CandleSeries()
		{
		}

		/// <summary>
		/// Создать <see cref="CandleSeries"/>.
		/// </summary>
		/// <param name="candleType">Тип свечки.</param>
		/// <param name="security">Инструмент, по которому необходимо формировать свечки.</param>
		/// <param name="arg">Параметр формирования свечки. Например, для <see cref="TimeFrameCandle"/> это значение <see cref="TimeFrameCandle.TimeFrame"/>.</param>
		public CandleSeries(Type candleType, Security security, object arg)
		{
			if (candleType == null)
				throw new ArgumentNullException("candleType");

			if (security == null)
				throw new ArgumentNullException("security");

			if (arg == null)
				throw new ArgumentNullException("arg");

			Security = security;
			CandleType = candleType;
			Arg = arg;
			WorkingTime = security.CheckExchangeBoard().WorkingTime;
		}

		/// <summary>
		/// Инструмент, по которому необходимо формировать свечки.
		/// </summary>
		public Security Security { get; set; }

		/// <summary>
		/// Тип свечки.
		/// </summary>
		public Type CandleType { get; set; }

		/// <summary>
		/// Параметр формирования свечки. Например, для <see cref="TimeFrameCandle"/> это значение <see cref="TimeFrameCandle.TimeFrame"/>.
		/// </summary>
		public object Arg { get; set; }

		private ICandleManager _candleManager;

		/// <summary>
		/// Менеджер свечек, который зарегистрировал данную серию.
		/// </summary>
		public ICandleManager CandleManager
		{
			get { return _candleManager; }
			set
			{
				if (value != _candleManager)
				{
					if (_candleManager != null)
					{
						_candleManager.Processing -= CandleManagerProcessing;
						_candleManager.Stopped -= CandleManagerStopped;
					}

					_candleManager = value;

					if (_candleManager != null)
					{
						_candleManager.Processing += CandleManagerProcessing;
						_candleManager.Stopped += CandleManagerStopped;
					}
				}
			}
		}

		// используется RealTimeCandleBuilderSource
		internal bool IsNew { get; set; }

		/// <summary>
		/// Событие обработки свечки.
		/// </summary>
		public event Action<Candle> ProcessCandle;

		/// <summary>
		/// Событие окончания обработки серии.
		/// </summary>
		public event Action Stopped;

		private WorkingTime _workingTime;

		/// <summary>
		/// Граница времени, в пределах которой должны транслироваться свечки для данной серии.
		/// </summary>
		public WorkingTime WorkingTime
		{
			get { return _workingTime; }
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				_workingTime = value;
			}
		}

		private DateTime _from = DateTime.MinValue;

		/// <summary>
		/// Начальная дата, с которой необходимо получать данные.
		/// </summary>
		public DateTime From
		{
			get { return _from; }
			set { _from = value; }
		}

		private DateTime _to = DateTime.MaxValue;

		/// <summary>
		/// Конечная дата, до которой необходимо получать данные.
		/// </summary>
		public DateTime To
		{
			get { return _to; }
			set { _to = value; }
		}

		private void CandleManagerStopped(CandleSeries series)
		{
			if (series == this)
				Stopped.SafeInvoke();
		}

		private void CandleManagerProcessing(CandleSeries series, Candle candle)
		{
			if (series == this)
				ProcessCandle.SafeInvoke(candle);
		}

		/// <summary>
		/// Освободить занятые ресурсы.
		/// </summary>
		protected override void DisposeManaged()
		{
			base.DisposeManaged();

			if (CandleManager != null)
				CandleManager.Stop(this);
		}

		/// <summary>
		/// Получить строковое представление.
		/// </summary>
		/// <returns>Строковое представление.</returns>
		public override string ToString()
		{
			return CandleType.Name + "_" + Security + "_" + (Arg == null ? string.Empty : Arg.ToString().Replace(":", "-"));
		}

		/// <summary>
		/// Загрузить настройки.
		/// </summary>
		/// <param name="storage">Хранилище настроек.</param>
		public void Load(SettingsStorage storage)
		{
			var trader = ConfigManager.GetService<ITrader>();
			if (trader == null)
				throw new InvalidOperationException("Нет информации о шлюзе.");

			var securityId = storage.GetValue<string>("SecurityId");
			Security = trader.Securities.First(s => s.Id == securityId);

			CandleType = storage.GetValue<Type>("CandleType");
			Arg = storage.GetValue<object>("Arg");

			From = storage.GetValue<DateTime>("From");
			To = storage.GetValue<DateTime>("To");
			WorkingTime = storage.GetValue("WorkingTime", Security.ExchangeBoard.WorkingTime);
		}

		/// <summary>
		/// Сохранить настройки.
		/// </summary>
		/// <param name="storage">Хранилище настроек.</param>
		public void Save(SettingsStorage storage)
		{
			storage.SetValue("SecurityId", Security.Id);

			storage.SetValue("CandleType", CandleType.AssemblyQualifiedName);
			storage.SetValue("Arg", Arg);

			storage.SetValue("From", From);
			storage.SetValue("To", To);
			storage.SetValue("WorkingTime", WorkingTime);
		}
	}
}